package com.atguigu.tingshu.user.service.impl;

import cn.hutool.core.util.IdUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.atguigu.tingshu.common.constant.RabbitConstant;
import com.atguigu.tingshu.common.constant.RedisConstant;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.util.AuthContextHolder;
import com.atguigu.tingshu.common.util.MongoUtil;
import com.atguigu.tingshu.model.user.UserListenProcess;
import com.atguigu.tingshu.user.service.UserListenProcessService;
import com.atguigu.tingshu.vo.album.TrackStatMqVo;
import com.atguigu.tingshu.vo.user.UserListenProcessVo;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import org.bson.types.ObjectId;
import org.joda.time.DateTime;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.temporal.ChronoUnit;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Service
@SuppressWarnings({"unchecked", "rawtypes"})
public class UserListenProcessServiceImpl implements UserListenProcessService {

    @Autowired
    private MongoTemplate mongoTemplate;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private RabbitTemplate rabbitTemplate;


    // 查询声音的播放进度
    @Override
    public BigDecimal getTrackBreakSecond(Long trackId) {
        // 1. 去mongoDB 查询 用户Id  + trackId
        Long userId = AuthContextHolder.getUserId();
        UserListenProcess listenProcess = mongoTemplate
                .findOne(Query.query(Criteria.where("userId").is(userId)
                        .and("trackId").is(trackId)), UserListenProcess.class);

        // 第一次播放 查询不到 返回 0
        if (listenProcess == null) {
            // 2. 如果没有查询到，则返回0
            return BigDecimal.ZERO;
        }

        // 更新声音和专辑的的播放数
        // 远程调用性能比较差 所以选择 MQ

        // 播放量更新逻辑
        // 同一个用户,同一个声音截止到今天为止只能发送一次更新的消息
        // 发送消息 封装专辑id 声音id 到album服务监听器
        // 借助 redis 的 bitmap  // userId 当key  偏移量 为 trackId 设置为1则认为已经发送过消息 不再发送
        String key = RedisConstant.TRACK_STAT_IDEM + userId;
        // 避免重发发送消息 ,判断是否已经发送过消息
        Boolean exists = redisTemplate.opsForValue().getBit(key, trackId);
        if (!exists) {
            // 不存在则可以发送消息
            // 记录bitmap
            redisTemplate.opsForValue().setBit(key, trackId, true);
            // 设置key的过期时间
            Long expireTime = new DateTime().withTimeAtStartOfDay().plusDays(1).toDate().getTime()- System.currentTimeMillis();
            redisTemplate.expire(key, expireTime, TimeUnit.MILLISECONDS);
            // 发送消息
            TrackStatMqVo trackStatMqVo = new TrackStatMqVo();
            // 生成业务编号
            trackStatMqVo.setBusinessNo(IdUtil.getSnowflakeNextIdStr());
            // todo  第一次播放可能获取不到(需要远程调用才能获取) 先不传
            // trackStatMqVo.setAlbumId(listenProcess.getAlbumId());
            // 设置业务数据
            trackStatMqVo.setTrackId(trackId);
            // 设置业务数据
            trackStatMqVo.setStatType(SystemConstant.TRACK_STAT_PLAY);
            // 设置更新数目 1
            trackStatMqVo.setCount(1);
            // 发送MQ消息
            rabbitTemplate.convertAndSend(RabbitConstant.ALBUM_EXCHANGE, RabbitConstant.TRACK_STAT_RK, trackStatMqVo);
        }
        return listenProcess.getBreakSecond();
    }

    // 保存用户声音的播放进度
    @Override
    public void updateListenProcess(UserListenProcessVo userListenProcessVo) {

        // 判断该用户的这个声音的播放记录是否存在 根据userId  trackId
        Long trackId = userListenProcessVo.getTrackId();
        Long userId = AuthContextHolder.getUserId();
        UserListenProcess listenProcess = mongoTemplate
                .findOne(Query.query(Criteria.where("userId").is(userId)
                        .and("trackId").is(trackId)), UserListenProcess.class);
        if (listenProcess == null) {
            // 第一次播放 则 保存记录
            listenProcess = new UserListenProcess();
            // 设置id
            listenProcess.setId(ObjectId.get().toString());
            listenProcess.setUserId(userId);
            listenProcess.setTrackId(trackId);
            listenProcess.setAlbumId(userListenProcessVo.getAlbumId());
            listenProcess.setBreakSecond(userListenProcessVo.getBreakSecond());
            listenProcess.setIsShow(1);
            listenProcess.setCreateTime(new Date());
            listenProcess.setUpdateTime(new Date());

        } else {
            // 不是第一次则更新
            listenProcess.setBreakSecond(userListenProcessVo.getBreakSecond());
            listenProcess.setUpdateTime(new Date());

        }
        mongoTemplate.save(listenProcess);
    }

    // 查询用户最近播放的声音
    @Override
    public JSONObject getLatelyTrack() {

        // 1. 查询一个数据  mongoDB
        Long userId = AuthContextHolder.getUserId();
        UserListenProcess listenProcess = mongoTemplate
                .findOne(Query.query(Criteria.where("userId").is(userId))
                                .with(Sort.by(Sort.Direction.DESC, "updateTime"))
                                .with(Pageable.ofSize(1).withPage(0))
                        , UserListenProcess.class);
        JSONObject json = new JSONObject();
        // 如果查询不到 则 返回一个推荐的结果  可以随机的生成
        if (listenProcess == null) {
            json.put("albumId", "1631");
            json.put("trackId", "51945");
        }else{

            json.put("albumId", listenProcess.getAlbumId());
            json.put("trackId", listenProcess.getTrackId());
        }
        return json;
    }

}
